home *** CD-ROM | disk | FTP | other *** search
- /* Copyright 1984 by the Massachusetts Institute of Technology */
-
- /*
- Copyright Cornell University 1986. All rights are reserved.
-
- As of 4/10/86:
- This source file may have no changes from the M.I.T original
- other than this notice; but it has been tested as part of
- Cornell's Aztec-C port. See notice.h
- */
-
- /* See permission and disclaimer notice in file "notice.h" */
-
- #include <notice.h>
- #include "tftp.h"
-
- extern int tntftp(), tntfdn();
-
- extern int (*tfs_alert)();
- extern int (*tfs_done)();
-
- extern char macfile[]; /* for Macintosh file name translation */
-
- extern int ntftps;
-
-
- extern int tfstate;
- extern long refusedt; /* time of most recent transfer refusal */
-
- extern unsigned NDEBUG;
-
- /* the tftp server code */
-
- /* Modified 12/23/83 to upcall a "done" function when the transfer is
- complete. Modified 1/11/84 to detect and discard duplicate requests
- to open a tftp connection. Fixed file open calls to use only binary mode
- (was making netascii transfers fail); fixed bug in counting number of
- tftp connections in progress; changed calls to send error packets to
- use incoming packet and socket number where appropriate, 1/13/84.
- Added test to discard duplicate requests that match current connections,
- that arrived before user refused a request or before discovery that
- file can't be transferred.
- <J. H. Saltzer>
- 1/24/84 - added octet mode which is the same as image mode.
- <John Romkey>
- 3/21/84 - corrected several places in the code where cn->tf_expected
- was referenced as cn->tf_expect and caused problems with the new
- compiler.
- <John Romkey>
- 4/12/84 - in tfsread() fixed call to udp_alloc() which was missing
- the option length parameter.
- <John Romkey>
- 12/21/84 - in tfsread() fixed buffer swapping code to prevent loss
- of one packet buffer on each transfer.
- <J. H. Saltzer>
- */
-
- #define MAXTFTPS 1
-
- UDPiopb tfspb; /* control block for TFTP listener socket */
- char tfsbuf[MACUDPLEN]; /* MacTCP read buffer */
- StreamPtr tfsstream; /* stream ptr for listener socket */
- int tfs_read_req; /* server read requests */
- int tfs_read_comp; /* server read completions */
- int tfsdata; /* data has arrived */
-
- struct tfconn tfsconn; /* tftp control connection struct */
- struct tfconn tftpconn; /* tftp transfer connection struct */
-
- UDPiopb tftppb; /* control block for TFTP transfer socket */
- char tftpbuf[MACUDPLEN]; /* MacTCP read buffer */
- StreamPtr tftpstream; /* stream ptr for transfer socket */
- int tftp_read_req; /* server read requests */
- int tftp_read_comp; /* server read completions */
- int tftpdata; /* data has arrived */
-
- extern char * malloc();
- unsigned long getmyA5();
-
- /* ioCompletion routine for the tftp listener on the server socket */
-
- void tfs_read_done(udp_read)
- UDPiopb *udp_read;
- {
- unsigned long oldA5;
-
- oldA5 = getmyA5();
-
- tfsdata = TRUE;
- tfs_read_comp++;
-
- setA5(oldA5);
- }
-
-
- /* ioCompletion routine for the tftp transfer socket */
-
- void tftp_read_done(udp_read)
- UDPiopb *udp_read;
- {
- unsigned long oldA5;
-
- oldA5 = getmyA5();
-
- tftpdata = TRUE;
- tftp_read_comp++;
-
- setA5(oldA5);
- }
-
- udp_release()
- {
- UDPiopb relPB;
- OSErr errcode;
-
- if (!tfsstream)
- return(-1);
-
- relPB.ioCRefNum = ipp_refnum;
- relPB.csCode = UDPRelease;
- relPB.udpStream = tfsstream;
-
- if (errcode = PBControl(&relPB, (Boolean) FALSE))
- error("udp release failed");
- }
-
-
- /* mtcp_tfsinit(alert, done) - initialize the tftp server. This opens a UDP
- connection but does not turn on the server. That needs to done by
- an explicit call to tfs_on().
-
- alert() is a function which the server will call whenever it receives
- request for a transfer. This function will be called int he following
- way:
- alert(ip_addr, file_name, direction)
-
- alert() should return TRUE if it wishes to allow the transfer and
- FALSE otherwise. done() is a function that the server will
- call to inform the invoker that this file transfer is complete or
- aborted.
- */
-
- mtcp_tfsinit(alert, done)
- int (*alert)();
- int (*done)();
- {
- OSErr errcode;
- extern short macipopen;
-
- if (!macipopen) {
- if (macip_init())
- return(-1);
- }
- tfspb.ioCRefNum = ipp_refnum;
- tfspb.csCode = UDPCreate;
- tfspb.csParam.create.rcvBuff = &tfsbuf[0];
- tfspb.csParam.create.rcvBuffLen = MACUDPLEN;
- tfspb.csParam.create.notifyProc = (ProcPtr) udp_event;
- tfspb.csParam.create.localPort = TFTPSOCK;
-
- if (errcode = PBControl(&tfspb, (Boolean) FALSE)) {
- if (errcode != duplicateSocket)
- /* skip message if socket already opened */
- error("tftp: UDPCreate failed");
- return(-1);
- }
- tfsstream = tfspb.udpStream;
- exit_hook(udp_release);
-
- if (mttfmkcn(&tfsconn, PUT, ASCII)) {
- /* make one connection block */
- return(-1);
- }
- tfsconn.stream = tfsstream;
-
- tfspb.csCode = UDPRead;
- tfspb.ioCompletion = tfs_read_done;
- tfspb.csParam.receive.timeOut = 0;
- if (errcode = PBControl(&tfspb, (Boolean) TRUE)) {
- error("tftp: no UDPRead");
- }
- tfs_read_req++;
-
- tfs_done = done;
- tfs_alert = alert;
- return(FALSE);
- }
-
- /* handle an incoming tftp packet. This involves opening a udp connection
- (immediately so that we can report errors). If the server is OFF
- then the tftp will be refused; otherwise more checking will be done.
- Call the alert function and verify that the "user" wishes to allow
- the tftp. Report an error if not. Finally, spawn a task to oversee
- the tftp and cleanup when it's done.
- */
- ip_addr tftphost; /* to check for duplicate connection request */
- udp_port tftpport; /* ditto */
-
- mtcp_tfshnd(ptreq, len, host, port, time)
- struct tfreq *ptreq;
- unsigned len;
- ip_addr host;
- udp_port port;
- unsigned short time;
- {
- unsigned nport;
- struct tfconn *cn = &tftpconn;
- char *file, *smode, *tmp;
- unsigned mode;
- OSErr errcode;
-
- /* If there is already a connection like this one, ignore duplicate
- request.
-
- if (udp_ckcon(host, port)) {
- return(0);
- }
- */
- /* since we don't have access to UDP with MacTCP we maintain this manually */
- if (host == tftphost && port == tftpport) {
- return(0);
- }
-
-
- /* If we refused a connection since this request got enqueued,
- assume this is a duplicate and discard it, so we don't bother the
- user with a duplicate question. (If we are unlucky, this might be
- a request from somewhere else that arrived while the user was
- thinking over the previous request. Tough; somewhere else will
- just have to try again.)
-
- */
-
- if (refusedt > time) {
- return(0);
- }
-
- /* The next question: Do we have room to do this transfer? */
-
- if (ntftps >= MAXTFTPS) {
- mtcp_tfrpyerr(&tfsconn, ERRTXT, "Too many connections.");
- return(0);
- }
-
- /* OK, let's check over the request more carefully. */
-
- if (ptreq->tf_op > WRQ) {
- #ifdef TFTPDEBUG
- if (NDEBUG & INFOMSG|NETERR|PROTERR)
- printf("TFTP SERVER: bad tftp opcode %u\n", ptreq->tf_op);
- #endif
- return(0);
- }
- file = &ptreq->tf_name[0];
- smode = file + strlen(file) + 1;
-
- for (tmp = smode; *tmp; tmp++)
- if (*tmp >= 'A' && *tmp <= 'Z')
- *tmp += 32;
-
- if (strcmp(smode, "image") == 0)
- mode = IMAGE;
- else if (strcmp(smode, "octet") == 0)
- mode = IMAGE;
- else if (strcmp(smode, "netascii") == 0)
- mode = ASCII;
- else {
- #ifdef TFTPDEBUG
- if (NDEBUG & INFOMSG|NETERR|PROTERR)
- printf("TFTP SERVER: Bad mode %s in req\n", smode);
- #endif
- mtcp_tfrpyerr(&tfsconn, ERRTXT, "Bad mode");
- return(0);
- }
-
- if (tfstate == OFF) {
- mtcp_tfrpyerr(&tfsconn, ERRTXT,"Transfers are not being accepted.");
- return(0);
- }
-
- if ((*tfs_alert)(host, file, ptreq->tf_op == RRQ ? PUT : GET) == 0) {
- mtcp_tfrpyerr(&tfsconn, ERRTXT, "Transfer refused.");
- refusedt = time;
- return(0);
- }
-
- /* It looks safe to try to open a connection. */
-
- if (mttfmkcn(cn, PUT, ASCII)) {
- /* Direction is a dummy for now */
- error("TFTP SERVER: Can't make connection, ignoring request");
- return(0);
- }
-
- #ifdef UDPFUNC
- cn->tf_udp = udp_open(host, port, udp_socket(), tftp_read_done, cn);
-
- if (cn->tf_udp == NULL) {
- error("TFTP SERVER: Can't open udp connection, ignoring request");
- mtcp_tfcleanup(cn);
- return(0);
- }
- #else
- tftppb.ioCRefNum = ipp_refnum;
- tftppb.csCode = UDPCreate;
- tftppb.csParam.create.rcvBuff = &tftpbuf[0];
- tftppb.csParam.create.rcvBuffLen = MACUDPLEN;
- tftppb.csParam.create.notifyProc = (ProcPtr) udp_event;
- tftppb.csParam.create.localPort = udp_socket();
-
- if (errcode = PBControl(&tftppb, (Boolean) FALSE)) {
- error("tftp: couldn't open UDP");
- }
- cn->tf_udp = &tftppb;
- cn->tf_host = host;
- cn->tf_port = port;
- tftpstream = tftppb.udpStream;
- cn->stream = tftpstream;
-
- /* and set up a read */
- tftppb.csCode = UDPRead;
- tftppb.ioCompletion = tftp_read_done;
- tftppb.csParam.receive.timeOut = 0;
- if (errcode = PBControl(&tftppb, (Boolean) TRUE)) {
- error("tftp: no UDPRead");
- }
- #endif
-
- cn->tf_mode = mode;
- cn->tf_state = INIT;
- macpath(file, &macfile[0]);
- if (ptreq->tf_op == RRQ) {
- cn->tf_dir = PUT;
- cn->tf_haveport = TRUE;
-
- cn->tf_fd = fopen(&macfile[0], "r");
- if (cn->tf_fd == NULL) {
- #ifdef TFTPDEBUG
- if (NDEBUG & NETERR|PROTERR)
- printf("couldn't open file\n");
- #endif
- mtcp_tfudperr(cn, FNOTFOUND, NULL);
- refusedt = cticks;
- mtcp_tfcleanup(cn);
- (*tfs_done)(OFF);
- return(0);
- }
- tfssend(cn);
- }
- else {
- cn->tf_dir = GET;
- cn->tf_haveport = TRUE;
- cn->tf_fd = fopen(&macfile[0], "w");
- if (cn->tf_fd == NULL) {
- /* error("couldn't open file"); */
- mtcp_tfudperr(cn, ACCESS, NULL);
- refusedt = cticks;
- mtcp_tfcleanup(cn);
- (*tfs_done)(OFF);
- return(0);
- }
- tfsrcv(cn);
- }
- ntftps++;
- tftphost = host;
- tftpport = port;
- }
-
-
- tfsrcv(cn)
- struct tfconn *cn;
- {
- switch (cn->tf_state) {
- case INIT: {
- cn->tf_expected = 1;
- mtcp_tfsndack(cn, 0);
- cn->tf_state = DATAWAIT;
- break;
- }
- case RCVDATA: {
- cn->tf_state = DATAWAIT;
- break;
- }
- case RCVLASTDATA: {
- mtcp_tfcleanup(cn);
- (*tfs_done)(ON);
- ntftps--;
- tftphost = 0;
- tftpport = 0;
- break;
- }
- case TIMEOUT: {
- #ifdef TFTPDEBUG
- if (NDEBUG & TMO)
- printf("TFTP: Host not responding, giving up\n");
- #endif
- mtcp_tfudperr(cn, ERRTXT,
- "Retry limit exceeded, giving up");
- mtcp_tfcleanup(cn);
- (*tfs_done)(OFF);
- ntftps--;
- tftphost = 0;
- tftpport = 0;
- break;
- }
- default: {
- /* unknown state, kill it */
- mtcp_tfcleanup(cn);
- (*tfs_done)(OFF);
- ntftps--;
- tftphost = 0;
- tftpport = 0;
- break;
- }
- }
- }
-
-
- /* vars belong in conn struct */
-
- int flen;
- int tftpdone;
- char * pfill;
- char * psnd;
-
- tfssend(cn)
- struct tfconn *cn;
- {
- switch (cn->tf_state) {
- case INIT: {
- /* no connection, initialize */
-
- flen = NORMLEN;
- tftpdone = 0;
- cn->tf_expected = 0;
-
- psnd = cn->tf_outp; /* psnd is tftp_util's buffer */
- pfill = malloc(NORMLEN); /* pfill is ours */
- if (pfill == NULL) {
- mtcp_tfudperr(cn, ERRTXT, "Couldn't allocate packet.");
- #ifdef TFTPDEBUG
- if (NDEBUG & NETERR|PROTERR)
- printf("tfsread: couldn't allocate pfill\n");
- #endif
- mtcp_tfcleanup(cn);
- (*tfs_done)(OFF);
- }
- /* fill up a data packet */
- fillpacket(cn);
- /* and fall through to send the first packet */
- }
- case RCVACK: {
- cn->tf_expected++;
-
- /* Check if we're done */
- if (tftpdone) {
- mtcp_tfcleanup(cn);
- (*tfs_done)(ON);
- free(pfill);
- ntftps--;
- tftphost = 0;
- tftpport = 0;
- break;
- }
-
- /* If not, resume the loop */
- psnd = pfill; /* prepare to switch */
- pfill = cn->tf_outp; /* take tftp_util's buffer */
- cn->tf_outp = psnd; /* our buffer to tftp_util */
- mtcp_tfsndata(cn, flen);
- if (flen < NORMLEN)
- tftpdone = 1;
- else
- fillpacket(cn); /* fill the next packet as we wait for ACK */
- break;
- }
- case TIMEOUT: {
- #ifdef TFTPDEBUG
- if (NDEBUG & TMO)
- printf("TFTP: Host not responding, giving up\n");
- #endif
- mtcp_tfudperr(cn,
- ERRTXT, "Retry limit exceeded, giving up");
- mtcp_tfcleanup(cn);
- (*tfs_done)(OFF);
- free(pfill);
- ntftps--;
- tftphost = 0;
- tftpport = 0;
- break;
- }
- default: {
- /* something's wrong here */
- mtcp_tfcleanup(cn);
- (*tfs_done)(ON);
- free(pfill);
- ntftps--;
- tftphost = 0;
- tftpport = 0;
- break;
- }
- }
- }
-
-
- fillpacket(cn)
- struct tfconn *cn;
- {
- register char * datap;
- register char * endp;
-
- datap = (char *) tftp_data(pfill);
-
- flen = fread(datap, 1, NORMLEN, cn->tf_fd);
- if (cn->tf_mode == ASCII) {
- /* translate CR's to LF's */
-
- for (endp = datap + flen; datap < endp; datap++) {
- if (*datap == 0x0d)
- *datap = 0x0a;
- }
- }
- cn->tf_size += flen;
- }